You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
51 lines
2.1 KiB
51 lines
2.1 KiB
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { spawn } from "node:child_process";
|
|
import { sendStream, setHeader } from "h3";
|
|
import { getExportTaskForUser, markExportTaskExpired } from "#server/service/export/jobs";
|
|
|
|
export default defineWrappedResponseHandler(async (event) => {
|
|
const user = await event.context.auth.requireUser();
|
|
const idRaw = getRouterParam(event, "id");
|
|
const taskId = Number(idRaw);
|
|
if (!Number.isInteger(taskId) || taskId < 1) {
|
|
throw createError({ statusCode: 400, statusMessage: "无效的任务 id" });
|
|
}
|
|
|
|
const task = await getExportTaskForUser(taskId, user.id);
|
|
if (!task) {
|
|
throw createError({ statusCode: 404, statusMessage: "导出任务不存在" });
|
|
}
|
|
if (task.status !== "succeeded") {
|
|
throw createError({ statusCode: 409, statusMessage: "导出任务尚未完成" });
|
|
}
|
|
if (!task.expiresAt || task.expiresAt.getTime() <= Date.now()) {
|
|
await markExportTaskExpired(task.id, "导出结果已过期,请重新导出");
|
|
throw createError({ statusCode: 410, statusMessage: "导出结果已过期" });
|
|
}
|
|
if (!task.outputDir || !task.outputName) {
|
|
await markExportTaskExpired(task.id, "导出结果缺失,请重新导出");
|
|
throw createError({ statusCode: 410, statusMessage: "导出文件已丢失,请重新导出" });
|
|
}
|
|
|
|
const manifestPath = path.resolve(task.outputDir, "manifest.json");
|
|
if (!fs.existsSync(manifestPath)) {
|
|
await markExportTaskExpired(task.id, "导出文件已丢失,请重新导出");
|
|
throw createError({ statusCode: 410, statusMessage: "导出文件已丢失,请重新导出" });
|
|
}
|
|
|
|
const archiveName = `${task.outputName}.tar.gz`;
|
|
const tarProc = spawn("tar", ["-czf", "-", "-C", task.outputDir, "."], {
|
|
stdio: ["ignore", "pipe", "pipe"],
|
|
});
|
|
tarProc.on("exit", async (code) => {
|
|
if (code === 0) {
|
|
return;
|
|
}
|
|
await markExportTaskExpired(task.id, "导出文件打包失败,请重新导出");
|
|
});
|
|
|
|
setHeader(event, "Content-Type", "application/gzip");
|
|
setHeader(event, "Content-Disposition", `attachment; filename="${archiveName}"`);
|
|
return sendStream(event, tarProc.stdout);
|
|
});
|
|
|